package com.ruoyi.common.core;

import com.ruoyi.common.exception.ProcessStopException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 计算进程 管理,用于计算进程的新建,终止等
 *
 * 通过sseid 唯一识别一个线程
 */
@Service
@Slf4j
public class CalcThreadManager implements ApplicationContextAware {
    private static Map<String, List<Process>> cmdCache = new ConcurrentHashMap();
    private static Map<String, Future> threadCache = new ConcurrentHashMap();
    private static String PREFIX="PROCESS:";

    private static RedisTemplate redisTemplate;


    //加锁保证 终止和 增加 线程
    private static Lock lock = new ReentrantLock();

    public static void addProcess(String sseId,Process obj) throws ProcessStopException {
        if (!StringUtils.hasLength(sseId)) {
            return;
        }
        Object statusKey = redisTemplate.opsForValue().get(PREFIX + sseId);
        if (statusKey != null) {
            //线程已终止，不得添加
            throw new ProcessStopException();
        }
        log.info("缓存计算exe线程：{}",sseId);
        lock.lock();
        try {
            if (cmdCache.containsKey(sseId)) {
                List<Process> processList = cmdCache.get(sseId);
                log.info("{}:{}", sseId, processList.size());
                processList.add(obj);
            } else {
                List<Process> objects = new ArrayList<>();
                objects.add(obj);
                cmdCache.put(sseId, objects);

            }
        }finally {
            lock.unlock();
        }
    };

    public static void addThread(String sseId,Future obj) {
        if (!StringUtils.hasLength(sseId)) {
            return;
        }
        log.info("缓存计算threadCache：{}",sseId);
        threadCache.put(sseId, obj);
    };



    //取消线程  并 终止 sse
    public static void cancelProcess(String sseId) {
        if (!StringUtils.hasLength(sseId)) {
            return;
        }
        redisTemplate.opsForValue().set(PREFIX+sseId,"1",10, TimeUnit.MINUTES);
        //加锁 防止线程进入
        lock.lock();
        try {

            Future future = threadCache.get(sseId);
            if (null != future) {
                future.cancel(true);
            }

            List<Process> cacheObj = cmdCache.get(sseId);
            if (null != cacheObj) {
                for (Process process : cacheObj) {
                    process.destroy();
                }
            }
            cmdCache.remove(sseId);
        }finally {
            lock.unlock();
        }

    };

    //清除线程  并 终止 sse
    public static void clearProcess(String sseId) {
        cmdCache.remove(sseId);
        threadCache.remove(sseId);
        redisTemplate.delete(PREFIX+sseId);
    };

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        redisTemplate = (RedisTemplate)applicationContext.getBean("redisTemplate");
    }
}
